﻿//============================================================================================
/*
 * @brief 有限状态机 - 分组状态。
 * 
 *********************************************************************************************/

using System.Collections.Generic;

namespace Imagine.Infrastructure.FiniteStateMachines
{
    /// <summary>
    /// 有限状态机 - 分组状态。
    /// </summary>
    public interface IFSMGroupState : IFSMState
    {
        IFSMState DefaultState { get; }
        IFSMState CurrentState { get; }
        void      AddState(IFSMState      state);
        void      SetDefaultState(string? stateName);
        void      ChangeState(string?     stateName);
    }

    /// <summary>
    /// 有限状态机 - 分组状态。
    /// </summary>
    public class FSMGroupState : FsmState, IFSMGroupState
    {
        private readonly Dictionary<string?, IFSMState> _states = new Dictionary<string?, IFSMState>();

        protected FSMGroupState(string? name) : base(name) { }

        public IFSMState DefaultState { get; private set; }
        public IFSMState CurrentState { get; private set; }

        public new static IFSMGroupState Create(string? name) => new FSMGroupState(name);

        public void AddState(IFSMState state)
        {
            if (state == null)
                return;

            _states.Add(state.Name, state);

            if (_states.Count == 1)
                SetDefaultState(state.Name);
        }

        public void SetDefaultState(string? stateName)
        {
            if (!_states.ContainsKey(stateName))
                return;

            DefaultState = _states[stateName];
            CurrentState = DefaultState;
        }

        protected override void OnEnter() => CurrentState?.Enter();

        protected override void OnUpdate()
        {
            if (CurrentState == null)
                return;

            CurrentState.Update();

            if (CurrentState.CheckCondition(out var nextStateName))
            {
                ChangeState(nextStateName);
            }
        }

        protected override void OnExit() => CurrentState?.Exit();

        public void ChangeState(string? stateName)
        {
            if (!_states.TryGetValue(stateName, out var state))
                return;

            CurrentState.Exit();
            state.Enter();
            CurrentState = state;
        }
    }
}